<?php
namespace app;

use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\exception\ErrorException;
use think\exception\Handle;
use think\exception\HttpException;
use think\exception\HttpResponseException;
use think\exception\ValidateException;
use think\Response;
use Throwable;

/**
 * 应用异常处理类
 */
class ExceptionHandle extends Handle
{
    /**
     * 不需要记录信息（日志）的异常类列表
     * @var array
     */
    protected $ignoreReport = [
        HttpException::class,
        HttpResponseException::class,
        ModelNotFoundException::class,
        DataNotFoundException::class,
        ValidateException::class,
    ];

    /**
     * 记录异常信息（包括日志或者其它方式记录）
     *
     * @access public
     * @param  Throwable $exception
     * @return void
     */
    public function report(Throwable $exception): void
    {
        // 使用内置的方式记录异常日志
        parent::report($exception);
    }

    /**
     * Render an exception into an HTTP response.
     *
     * @access public
     * @param \think\Request   $request
     * @param Throwable $e
     * @return Response
     */
    public function render($request, Throwable $e): Response
    {
        // 添加自定义异常处理机制
        // 参数验证错误
        if ($e instanceof ValidateException) {
            //return json($e->getError(), 422);
            return json(['code' => 20001, 'message' => $e->getError()]);
        }

        // 请求异常
        if ($e instanceof HttpException) {
            //return response($e->getMessage(), $e->getStatusCode());
            return json(['code' => $e->getStatusCode(), 'message' => $e->getMessage()], $e->getStatusCode());
        }

        // 数据为空
        if ($e instanceof ModelNotFoundException || $e instanceof DataNotFoundException) {
            return json(['code' => 410, 'message' => $e->getMessage()], 410);
        }

        // 异常提醒
        if (!$this->isIgnoreReport($e)) {
            $name    = $request->ip();
            $user_id = !empty($request->user) ? $request->user->id : 0;
            if ($user_id != 1) {
                $value = cache($name) ?? 0;
                if ($value >= 10) {
                    //return json(['code' => 110, 'message' => '风险提示'], 500);
                }
                //cache($name, ++$value, 86400);
            } else {
                return json([
                    'code'    => $e->getCode(),
                    'message' => $e->getMessage(),
                    'file'    => $e->getFile(),
                    'line'    => $e->getLine()
                ], 500);
            }

            $errorArr['content']  = '['. date('Y-m-d H:i:s') . ']error： ' . $user_id. "\n";
            $errorArr['content'] .= "请求 URL: https://{$request->host()}{$request->url()} \n";
            $errorArr['content'] .= "请求方法: " . $request->method() . "\n";
            $errorArr['content'] .= "请求标头: " . json_encode($request->header())  . "\n";
            $errorArr['content'] .= "请求主体: " . json_encode($request->param()) . "\n";
            $errorArr['content'] .= "code:" . $e->getCode() . "\n";
            $errorArr['content'] .= "message:" . $e->getMessage() . "\n";
            $errorArr['content'] .= "file:" . $e->getFile() . "\n";
            $errorArr['content'] .= "line:" . $e->getLine() . "\n";
            //Dingtalk::message($errorArr);
        }

        // 语法错误
        //if ($e instanceof \ParseError) {
        //    return json(['code' => 411, 'message' => $e->getMessage()], 411);
        //}

        // 数据库错误
        if ($e instanceof DbException) {
            return json(['code' => 412, 'message' => $e->getMessage()], 412);
        }

        // 数据类型或参数
        if ($e instanceof \InvalidArgumentException || $e instanceof ErrorException) {
            return json(['code' => 413, 'message' => $e->getMessage()], 413);
        }

        // 其他错误交给系统处理
        return parent::render($request, $e);
    }
}
